package org.carl.component.job.core

import com.alibaba.fastjson.JSON
import com.xxl.job.core.biz.model.ReturnT
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor
import com.xxl.job.core.handler.annotation.XxlJob
import org.carl.component.job.constant.PlatForm
import org.carl.component.job.enums.ScheduleTypeEnum
import org.carl.component.job.service.JobConfigService
import org.carl.component.job.service.JobInfoService
import org.carl.component.job.vo.XxlJobInfo
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
import org.springframework.core.MethodIntrospector
import org.springframework.core.annotation.AnnotatedElementUtils
import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Component
import java.lang.reflect.Method
import java.util.*

/**
 * email carl.chen@bk.ru
 * @Author: 陈青松
 * @Date: 2019/2/20 0:51
 */

@Component
@ConditionalOnBean(value = [XxlJobSpringExecutor::class])
open class XxljobInitialRunner : ApplicationContextAware {
    /**
     * applicationContext
     */
    private var applicationContext: ApplicationContext? = null

    override fun setApplicationContext(applicationContext: ApplicationContext) {
        this.applicationContext = applicationContext
        init()
    }

    /**
     * 任务配置类
     */
    @Autowired
    private val jobConfigService: JobConfigService? = null

    /**
     * 任务详细
     */
    @Autowired
    private val jobInfoService: JobInfoService? = null

    companion object {
        val LOG = LoggerFactory.getLogger(this.javaClass)
    }

    fun init() {
        LOG.info("自动注册xxl-job任务")
        //初始化登录
        jobConfigService!!.login()
        //初始化任务组
        jobConfigService!!.initGroupData()
        //注册本地任务组
        val returnT = jobConfigService!!.regLocalJobGroup()
        //注册不成功,跳过后续步骤
        if (null != returnT || (null != returnT && ReturnT.FAIL_CODE === returnT!!.code)) {
            LOG.error("注册任务组失败:${returnT!!.msg},将不再执行自动注册,请手动注册")
            return
        }
        //需要再次获取任务组
        jobConfigService!!.initGroupData()
        //初始化本地任务数据,为了确定任务组id
        jobConfigService!!.initLocalJobConfigData()
        //任务组id为空,不再执行
        if (null == PlatForm.LOCAL_GROUP_ID) {
            LOG.error("不存在当前工程的任务组,不执行自动注册!")
            return
        }
        //获取所有的joblist
        jobConfigService.initJobInfoList()
        val beanDefinitionNames =
            applicationContext!!.getBeanNamesForType(Any::class.java, false, true)
        for (beanDefinitionName in beanDefinitionNames) {
            val bean = applicationContext!!.getBean(beanDefinitionName)
            var annotatedMethods: Map<Method?, XxlJob?>? =
                null
            try {
                annotatedMethods = MethodIntrospector.selectMethods<XxlJob?>(
                    bean.javaClass
                ) { method ->
                    AnnotatedElementUtils.findMergedAnnotation(
                        method,
                        XxlJob::class.java
                    )
                }
            } catch (ex: Throwable) {
                LOG.error(
                    "xxl-job method-jobhandler resolve error for bean[$beanDefinitionName].",
                    ex
                )
            }
            if (annotatedMethods == null || annotatedMethods.isEmpty()) {
                continue
            }
            for ((executeMethod, xxlJob) in annotatedMethods) {
                val xxlJobInfoAnno = AnnotatedElementUtils.findMergedAnnotation(
                    executeMethod,
                    org.carl.component.job.annotation.XxlJobInfo::class.java
                )
                if(xxlJobInfoAnno==null){
                    LOG.warn("请为${executeMethod}添加@XxlJobInfo注解以便自动注册任务,将跳过本次执行")
                    continue
                }
                //判断本任务是否存在
                val extendXxlJobInfo = PlatForm.JOB_LIST?.find {
                    it.executorHandler.equals(xxlJob?.value)
                }
                val xxlJobInfo = XxlJobInfo()
                xxlJobInfo.id = xxlJobInfoAnno?.id
                xxlJobInfo.jobGroup = PlatForm.LOCAL_GROUP_ID!!
                xxlJobInfo.scheduleType = xxlJobInfoAnno!!.scheduleType.name
                xxlJobInfo.scheduleConf = xxlJobInfoAnno!!.scheduleConf
                xxlJobInfo.jobDesc = xxlJobInfoAnno!!.jobDesc
                xxlJobInfo.author = xxlJobInfoAnno!!.author
                xxlJobInfo.updateTime = Date()
                xxlJobInfo.addTime = Date()
                xxlJobInfo.alarmEmail = xxlJobInfoAnno?.alarmEmail
                xxlJobInfo.executorRouteStrategy = xxlJobInfoAnno?.executorRouteStrategy
                xxlJobInfo.executorHandler = xxlJob!!.value
                xxlJobInfo.executorParam = xxlJobInfoAnno?.executorParam
                xxlJobInfo.executorBlockStrategy = xxlJobInfoAnno?.executorBlockStrategy
                xxlJobInfo.executorTimeout = xxlJobInfoAnno?.executorTimeout
                xxlJobInfo.executorFailRetryCount = xxlJobInfoAnno?.executorFailRetryCount
                xxlJobInfo.glueType = xxlJobInfoAnno?.glueType
                xxlJobInfo.glueSource = xxlJobInfoAnno?.glueSource
                xxlJobInfo.glueRemark = xxlJobInfoAnno?.glueRemark
                xxlJobInfo.glueUpdatetime = Date()
                xxlJobInfo.childJobId = xxlJobInfoAnno?.childJobId
                xxlJobInfo.triggerStatus = xxlJobInfoAnno?.triggerStatus
                xxlJobInfo.misfireStrategy = xxlJobInfoAnno?.misfireStrategy
                //不存在任务
                if (null === extendXxlJobInfo) {
                    val responseEntity: ResponseEntity<String> = jobInfoService?.addJob(xxlJobInfo)!!
                    LOG.info("执行添加任务:${xxlJobInfo.id},执行结果:${responseEntity.body}")
                } else {
                    xxlJobInfo.id=extendXxlJobInfo.id
                    val responseEntity: ResponseEntity<String> = jobInfoService?.updateJob(xxlJobInfo)!!
                    LOG.info("执行更新任务:${xxlJobInfo.id},执行结果:${responseEntity.body}")
                }
            }
        }
    }
}